Inventory Reporting & Management
Background
The Inventory Reporting & Management API is useful to create detailed inventory reports of sites, rooms, and devices. Some examples include device aggregations, device queries, device count, and room & site information.
The API Playground is scoped to your authenticated user's Poly Lens access.
Deprecated Queries
Poly Lens APIs have evolved as we've worked to optimize the device querying experience.
Two queries, devices
and searchDevices
, are now deprecated. While both of these queries still work, they're not optimized for querying large batches of device data. The new deviceSearch
query implements pagination and supports returning results of more than 10k entries.
Query Devices using deviceSearch
deviceSearch
is a core query in the Lens API. It's used to retrieve details about all devices within your Poly Lens Account (Tenant) and is the primary entry point for device inventory, status, and metadata.
The deviceSearch
query returns results in a connection-based structure using edges
and nodes
. This pattern is a GraphQL standard for handling lists of data with support for pagination, sorting, and filtering.
edges
are a wrapper around the node (device). They allow us to use (or add) things like pagination and sort order, without changing the structure of the device data.nodes
are the actual thing we're asking for, such as a device and its metadata.
deviceSearch
uses the DeviceFindArgs
input type for argument parameters, which include:
filter
: The parameters to narrow down which devices are returnednextToken
:The continuation token (for pagination)pageSize
: The maximum number of result objects to include in the page results (min 1, max 5000, default 10)sort
: The direction and field name to sort the results
The deviceSearch
queries on this page progress from basic to more advanced examples.
Basic Query Example
We'll begin with a simple query that returns the following fields for all devices in your Poly Lens Account (Tenant):
name
: The user-assigned or default nameid
: The unique identifierconnected
:true
if currently connected to the network and communicating with Poly LenshardwareModel
: The hardware model namesoftwareVersion
: The current software version installed
By default, deviceSearch
returns 10 results per request. pageSize: 10
isn't auto-populated in the API Playground Variables field. You can adjust pageSize
to any value between 1 and 5000.
To keep the sample response concise, we'll change pageSize
to 2.
Test this query in the GraphQL Playground
query allDevices($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
hardwareModel
softwareVersion
}
}
}
}
Variables
{
"params": {
"pageSize": 2
}
}
Sample Response
{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "Poly Lens Desktop",
"id": "ce542b2b-0e3e-4f29-eab7-4d2243d14b42",
"connected": true,
"hardwareFamily": "Lens App Family",
"hardwareModel": "Lens Desktop",
"softwareVersion": "2.1.1.2761"
}
},
{
"node": {
"name": "DFR Dev Lab X70",
"id": "00e0db775ba0",
"connected": true,
"hardwareFamily": "Studio X Family Large",
"hardwareModel": "Studio X70",
"softwareVersion": "4.4.3.438012"
}
}
]
}
}
}
Pagination and pageInfo
Metadata
To manage pagination, use the pageInfo
object, which includes:
totalCount
: The total number of resultscountOnPage
: The number of results returned on this pagenextToken
: The token to retrieve the next page. Usenull
to return the first page.hasNextPage
:true
if there are more results available
Sorting Results with deviceSort
To sort results, use the deviceSort
input, which includes:
direction
: Sort order - ASC (Ascending) or DESC (Descending)name
: The name of the field to sort by (e.g.,id
,name
,hardwareModel
)
Using Filters to Target Specific Devices
Returning all devices in every query is usually inefficient and impractical. Most use cases require filtering or grouping the data to focus on specific device types, statuses, or configurations. The deviceSearch
query offers a comprehensive set of filter options to support various levels of granularity.
The following examples explore applying filters to narrow down your query results.
Filter by activeApplicationName
To identify the provider mode your Poly devices are running, use the activeApplicationName
field.
This is done by passing two filter variables:
field
: the field name to filter by (e.g.,activeApplicationName
)contains
: the field value to search for (e.g., "Zoom", "Microsoft", "Poly")
This filter effectively tells the API: "Return all devices where the activeApplicationName
field contains the string 'xyz'."
The query below asks for Poly devices running Zoom Rooms, the Zoom Rooms APK version, and includes pagination
. This includes Poly Touch Controllers that are paired to Poly Video Codecs running Zoom Rooms.
The provider name passed into the contains
field is case sensitive.
Test this query in the GraphQL Playground
query zoomDevices($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
serialNumber
hardwareModel
activeApplicationName
activeApplicationVersion
room {
name
floor
}
connections {
name
id
connected
}
}
}
pageInfo {
totalCount
countOnPage
nextToken
hasNextPage
}
}
}
Variables
{
"params": {
"pageSize": 2,
"filter": {
"contains": "Zoom",
"field": "activeApplicationName"
},
"sort": {
"fields": [
{
"direction": "ASC",
"name": "id"
}
]
}
}
}
Sample Response
{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "DFR StudioX70",
"id": "00f2cd543a5b",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X70",
"activeApplicationName": "Zoom Rooms",
"activeApplicationVersion": "6.1.0.5144",
"room": {
"name": "Jedi Enclave",
"floor": "2"
},
"connections": [
{
"name": "Poly TC8",
"id": "00e0ca2a5643",
"connected": false
},
{
"name": "Poly TC10",
"id": "00e0bc1ad311",
"connected": true
}
]
}
},
{
"node": {
"name": "Poly TC10",
"id": "00e0ab8803ab",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "TC10",
"activeApplicationName": "Zoom",
"activeApplicationVersion": "6.4.1.6706",
"room": {
"name": "Endor 501",
"floor": "5"
},
"connections": [
{
"name": "DFR Dev Lab G62",
"id": "00e0aa3ca3b6",
"connected": true
}
]
}
}
],
"pageInfo": {
"totalCount": 65,
"countOnPage": 2,
"nextToken": "NHU2MTybWpic2Jt",
"hasNextPage": true
}
}
}
}
Filter with OR:
Conditions
You can use the OR:
filter to match multiple activeApplicationName
values in a single request. This is helpful if you want to query all devices running either Microsoft Teams Rooms or Zoom Rooms.
This includes Poly Touch Controllers that are paired to Poly Video Codecs running Zoom Rooms.
Test this query in the GraphQL Playground
query msftAndZoomDevices($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
serialNumber
hardwareModel
activeApplicationName
activeApplicationVersion
room {
name
floor
}
connections {
name
id
connected
}
}
}
pageInfo {
countOnPage
totalCount
hasNextPage
nextToken
}
}
}
Variables
{
"params": {
"pageSize": 2,
"filter": {
"OR": [
{
"contains": "Zoom",
"field": "activeApplicationName"
},
{
"contains": "Microsoft",
"field": "activeApplicationName"
}
]
},
"sort": {
"fields": [
{
"direction": "ASC",
"name": "id"
}
]
}
}
}
Sample Response
{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "DFR Dev Lab X52",
"id": "00a0dc617b05",
"connected:" true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X52",
"activeApplicationName": "Microsoft Teams",
"activeApplicationVersion": "1449/1.0.96.2025031102",
"room": {
"name": "Endor 301",
"floor": "3"
},
"connections": [
{
"name": "Trio C60",
"id": "64162ab36978",
"connected": true
},
{
"name": "Poly TC10",
"id": "00a0ca3ab0b4",
"connected": true
}
]
}
},
{
"node": {
"name": "Poly TC8",
"id": "00e0ca521c23",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "TC8",
"activeApplicationName": "Zoom",
"activeApplicationVersion": "6.4.2.6801",
"room": {
"name": "Endor 101",
"floor": ""
},
"connections": [
{
"name": "DFR Studio X30",
"id": "00c5ef345e2d",
"connected": true
}
]
}
},
],
"pageInfo": {
"countOnPage": 2,
"totalCount": 33,
"hasNextPage": true,
"nextToken": "cHknJlcjBueTMwZg=="
}
}
}
}
Combine OR:
& AND:
Filters
To extend the previous example, you can filter devices based on both Provider Mode (activeApplicationName
) and Hardware Model (hardwareModel
) using a combination of OR:
and AND:
filters.
The following is a query that returns devices where:
activeApplicationName
contains Zoom or Microsoft, andhardwareModel
contains Studio X
Test this query in the GraphQL Playground
query StudioXZoomMsft($params: DeviceFindArgs) {
deviceSearch(params: $params) {
edges {
node {
name
id
connected
serialNumber
hardwareModel
activeApplicationName
activeApplicationVersion
room {
name
floor
}
connections {
name
id
connected
}
}
}
pageInfo {
countOnPage
totalCount
hasNextPage
nextToken
}
}
}
Variables
{
"params": {
"pageSize": 2,
"filter": {
"AND": [
{
"contains": "Studio X",
"field": "hardwareModel"
},
{
"OR": [
{
"contains": "Zoom",
"field": "activeApplicationName"
},
{
"contains": "Microsoft",
"field": "activeApplicationName"
}
]
}
]
},
"sort": {
"fields": [
{
"direction": "ASC",
"name": "id"
}
]
}
}
}
Sample Response
{
"data": {
"deviceSearch": {
"edges": [
{
"node": {
"name": "DFR Dev Lab X52",
"id": "00a0dc617b05",
"connected:" true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X52",
"activeApplicationName": "Microsoft Teams",
"activeApplicationVersion": "1449/1.0.96.2025031102",
"room": {
"name": "Endor 301",
"floor": "3"
},
"connections": [
{
"name": "Trio C60",
"id": "64162ab36978",
"connected": true
},
{
"name": "Poly TC10",
"id": "00a0ca3ab0b4",
"connected": true
}
]
},
},
{
"node": {
"name": "DFR StudioX70",
"id": "00f2cd543a5b",
"connected": true,
"serialNumber": "superSecretSerialNumber",
"hardwareModel": "Studio X70",
"activeApplicationName": "Zoom Rooms",
"activeApplicationVersion": "6.1.0.5144",
"room": {
"name": "Jedi Enclave",
"floor": "2"
},
"connections": [
{
"name": "Poly TC8",
"id": "00e0ca2a5643",
"connected": false
},
{
"name": "Poly TC10",
"id": "00e0bc1ad311",
"connected": true
}
]
},
}
],
pageInfo": {
"countOnPage": 2,
"totalCount": 15,
"hasNextPage": true,
"nextToken": "Z2F4eHprc3eG92ZWE0NGt4"
}
}
}
}
Querying CCX Hardware Revisions
If you're using Poly Lens to manage your CCX inventory and need to identify which CCX 400 & 500 hardware revisions have been deployed, you can use the Lens APIs to aggregate this data programmatically.
There are two ways to accomplish the task using Lens APIs:
- Use the GraphQL Playground to run the query and export the results to
.csv
.- This approach is best for those who don't write code or scripts.
- You'll use Excel to format the
.csv
results.
- Grab the example Query and Arguments from the GraphQL Playground and implement them into your scripting language of choice.
- This requires more upfront work but removes the need to parse the data through external tools.
This article details using the GraphQL Playground to query the data and export the results to .csv
.
For those using the GraphQL Playground, we'll break the process down into these steps:
The API Playground is scoped to your authenticated user's access. To scope the data to a specific tenant, you can either create an API Connection or pass a tenantId
directly into the arguments of the pre-configured example query.
Query Structure
We'll use the deviceSearch
query to return each CCX device's name
, hardwareModel
, macAddress
, hardwareRevision
, softwareVersion
, room
and site
. These fields provide the core details required to accomplish the task. If you don't use room or site assignments, or if certain fields aren't relevant to your use case, you can remove them from the query and proceed.
In the Variables section, we filter by hardwareModel
to return only CCX 400 and 500 devices. The pageSize
is set to 500 CCXs to retrieve more results per request and reduce the number of API calls, helping to avoid rate-limiting.
To determine the total number of CCX devices in your Account (Tenant), run the query and check the totalCount
field in the pageInfo
response.
If the totalCount
is less than 500, refer to Tenants with < 500 CCXs.
If the totalCount
exceeds 500, refer to the Tenants with > 500 CCXs.
Access this query in the GraphQL Playground
Tenants with < 500 CCXs
If pageCount
returned less than 500 devices, click the table icon in the Response
section of the user interface. The results will appear in a table view and display a .csv
download button. Download the .csv
and proceed to Formatting the .csv
Data in Excel.
Tenants with > 500 CCXs
The pageInfo
fields contain the information required to use pagination
. Of the four fields, nextToken
is the one we need to use.
The Variables
> params
> nextToken
field will be null
the first time you run the query.
Now, run the query and look at the Response
section. If the totalCount
exceeds the pageSize
, nextToken
will contain an alphanumeric string.
Click the table
icon and look at the edges
row. You'll see an option to download the .csv
results.
Copy the nextToken
string from the query response and paste it into the Variables
> params
> nextToken
field before running the query to fetch the next batch of results. Make sure you download the .csv
each time you run the query and fetch the next batch of results.
Continue copying the nextToken
, running the query, and downloading the csv
until the response returns nextToken
: null
.
Formatting the .csv
Data in Microsoft Excel
Each CCX we've queried has the same key
and value
format. The goal is to create a usable Excel table by filtering/parsing the unnecessary characters, removing the duplicate keys
, and creating a column with a single key
(as a header) for each CCX corresponding value
.
This section covers the more accessible, manual way to format the query results in Excel. If you're an Excel power user, this section won't be helpful for you. Feel free to skip it and perform the Excel formatting magic of your choice.
We'll start by ensuring we have a single .csv
as our primary document. If you have less than 500 devices and only one .csv
file, you saved a little work and should proceed to the Text to Columns Wizard.
If you have greater than 500 devices and have downloaded multiple .csv
files, open the first one and delete row A1
. This file will be our primary working document.
For each additional .csv
, the process remains the same. Open the file and cut/paste all rows (except A1
) into the primary document. After you've moved all rows to the primary document, the result/structure of the file will look similar to this.
Text to Columns Wizard
The data for each device is in the first cell of each row, even though it spans across the table. To filter and parse this information, select all in Column A
, click the Data
tab, and click Text to Columns
.
Text to Columns
has limitations, so we can't parse all characters in a single step. However, it gets us most of the way there.
Text to Columns - Step 1 of 3: Choose the Delimited
character type and click Next
.
Text to Columns - Step 2 of 3: In the Delimiters
section, select Comma
, Other
, and add a colon (:) into the field.
Text to Columns - Step 3 of 3: Select General
in the Column data format
field. Click Finish.
Creating Column Headers
The next step is to create column headers for the values
. First, insert a new row at the top of the table. Then, you can cut/paste the key
into the row's corresponding column or type it manually. The .csv
splits the site
name
and room
name
into separate columns. Combine these values into a single column header. Now, you can select and delete all columns containing the same key.
Removing Remaining Characters
The }
is the last character we need to remove. Using Find and Replace
, add a }
in the Find what
field and a blank space in the Replace with
field. Click Replace All
and the result is a cleanly formatted table.
Format as Table
Select all the data cells and use Format as Table
to make the table easier to read and filter. During this step, make sure to select My table has headers
.
You have now used the GraphQL Playground to query data from your Poly Lens Account (Tenant), parsed the results, and created a usable table to drill into the details. Nice work! 👏🏼
If you have questions about usage, authentication, or integration with the Poly Lens APIs, contact us.